#include <fstream>
#include <utility>
#include <iostream>
#include <sstream>
#include <ios>

#include <stdlib.h>

#include "driver.h"

Driver::Driver(int key, int seed, std::string& fname):
  _gen(fname),
  _coder(std::string("0198371"), seed) {

  _key = key;
  _seed = seed;
}

int Driver::DoEncrypt(const std::string& text, const std::string& bin,
    unsigned ammount) {
  std::ofstream outText(text.c_str());
  std::ofstream outBin(bin.c_str(), std::ios::binary);


  if (!outText) {
    std::cout << "Herota111" << std::endl;
    return -1;
  }

  // this is outside from the cycle for optmization purposes.
  //std::stringstream ss;
  //srand(1);
  //srand(_key);

  for(int i = 0; i < ammount; i++) {
    // update _coder's key with new value.
    //unsigned key = rand();

    //ss.clear();
    //ss.str(std::string());
    //ss << key;

    //std::string keyStr;
    //ss >> keyStr;

    //_coder.Coder::UpdateKey(keyStr);

    std::pair<std::string, int> current = _gen.GeneratePermutation();
    cpair enc = _coder.AESEncrypt(current.first);

    outText << "perm" << current.first << " " << " ind" << current.second
      << "end"<< std::endl;

    unsigned len = enc.second;
    outBin.write(reinterpret_cast<const unsigned char*>(&len), sizeof(len));
    outBin.write(enc.first, enc.second);

  }

  outBin.close();
  outText.close();

  return 0;
}

int Driver::DoDecrypt(const std::string& bin, const std::string& text) {
  std::ifstream inBin(bin.c_str(), std::ios::binary);
  std::ofstream outTxt(text.c_str());

  //srand(1);
  //srand(_key);
  //std::cout << "decr secret key "<< _key << std::endl;

  unsigned nbytes = 0;

  // this is outside from the cycle for optmization purposes.
  std::stringstream ss;

  int i = 0;
  while (!inBin.eof()) {
    inBin.read(reinterpret_cast<char *>(&nbytes), sizeof(nbytes));
    unsigned char* cipher = new unsigned char[nbytes];
    inBin.read(cipher, nbytes);

    //unsigned key = rand();

    //ss.clear();
    //ss.str(std::string());
    //ss << key;

    //std::string keyStr;
    //ss >> keyStr;

    //_coder.Coder::UpdateKey(keyStr);
    
    outTxt << _coder.AESDecrypt(cpair(cipher, nbytes)) << std::endl;
  }

  outTxt.close();
  inBin.close();

  return 0;
}
